﻿using EasyAdmin.DatabaseAccessor.SqlSugar;
using EasyCore.Reflection;
using EasyCore.UnitOfWork;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using static Org.BouncyCastle.Math.EC.ECCurve;
using System.Reflection;
using EasyAdmin.DatabaseAccessor.SqlSugar.Attributes;
using EasyAdmin.DatabaseAccessor.SqlSugar.Setting;
using EasyCore.App;
using EasyAdmin.DatabaseAccessor.SqlSugar.Seeds;
using System.Collections;
using System.Data;
using MathNet.Numerics.Differentiation;
using EasyCore.Entities.Auditing;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using EasyCore.Logging;
using System.Text.RegularExpressions;
using NPOI.SS.Formula.Functions;
using System.ComponentModel;
using Masuit.Tools.Reflection;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// SqlSugar 拓展类
    /// </summary>
    public static class SqlSugarServiceCollectionExtensions
    {
        /// <summary>
        /// 添加 SqlSugar 拓展
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        /// <param name="buildAction"></param>
        /// <returns></returns>
        public static IServiceCollection AddSqlSugar(this IServiceCollection services, SqlSugarSettings config, Action<ISqlSugarClient> buildAction = default)
        {
            return services.AddSqlSugar(new List<SqlSugarSettings> { config }, buildAction);
        }

        /// <summary>
        /// 添加 SqlSugar 拓展
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configs"></param>
        /// <param name="buildAction"></param>
        /// <returns></returns>
        public static IServiceCollection AddSqlSugar(this IServiceCollection services, List<SqlSugarSettings> configs, Action<ISqlSugarClient> buildAction = default)
        {   
            var configIdGroup = configs.GroupBy(it => it.ConfigId).ToList();
            foreach (var configId in configIdGroup)
            {
                if (configId.ToList().Count > 1) throw new Exception($"Sqlsugar连接配置ConfigId:{configId.Key}重复了");
            }
            List<ConnectionConfig> connectionConfigs = new List<ConnectionConfig>();
            connectionConfigs = configs.ToList<ConnectionConfig>();
            // 注册 SqlSugar 客户端
            services.AddScoped<ISqlSugarClient>(u =>
            {
                var sqlSugarClient = new SqlSugarClient(connectionConfigs);//配置数据库链接
                buildAction?.Invoke(sqlSugarClient);                
                return sqlSugarClient;
            });
            // 注册非泛型仓储
            services.AddScoped<ISqlSugarRepository, SqlSugarRepository>();
            // 注册 SqlSugar 仓储
            services.AddScoped(typeof(ISqlSugarRepository<>), typeof(SqlSugarRepository<>));
            services.AddScoped<IUnitOfWork, SqlSugarUnitOfWork>();//注册工作单元 
            services.AddSingleton<List<SqlSugarSettings>>(configs);//注入数据库配置
            return services;
        }

        /// <summary>
        /// 初始化数据库
        /// </summary>
        /// <param name="webApplication"></param>
        /// <returns></returns>
        public static WebApplication InitDatabase(this WebApplication app)
        {
            //获取数据库实体对象
            var entityTypes = AssemblyManager.FindTypes(m => m.IsClass && !m.IsInterface && !m.IsAbstract && m.IsDefined(typeof(SugarTable), false));
            if (entityTypes == null || !entityTypes.Any()) return app;


            var serviceScope = app.Services.CreateScope();
            //获得数据库客户端及数据库配置
            var sqlClient = serviceScope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
            var configs = serviceScope.ServiceProvider.GetRequiredService<List<SqlSugarSettings>>();
            if (configs == null || !configs.Any()) return app;
            if (configs != null && configs.Any())
            {
                foreach (var config in configs)
                {
                    if (config.IsInitDb) InitTables(sqlClient, config, entityTypes); //初始化表结构
                    if (config.IsSeedData) InitSeedData(sqlClient, config); //执行种子函数，初始化数据
                }
            }
            return app;
        }

        /// <summary>
        /// 自动初始化数据表
        /// </summary>
        public static void InitTables(ISqlSugarClient sqlClient, SqlSugarSettings config, Type[] entityTypes)
        {
            var sqlSurgarProvider = ((SqlSugarClient)sqlClient).GetConnection(config.ConfigId);
            sqlSurgarProvider.DbMaintenance.CreateDatabase();//创建数据库
            var db = ((SqlSugarClient)sqlClient).GetConnectionScope(config.ConfigId); //获得数据库对象   
            MoreSetting(db);//更多设置
            ExternalServicesSetting(db, config); //实体拓展配置,自定义类型多库兼容
            AopSetting(db);//aop配置
            FilterSetting(db);//过滤器配置
            foreach (var entityType in entityTypes)
            {
                var tenantAtt = entityType.GetCustomAttribute<TenantAttribute>();//获取Sqlsugar多租户特性
                var ignoreInit = entityType.GetCustomAttribute<IgnoreInitTableAttribute>();//获取忽略初始化特性
                if (ignoreInit != null) continue;//如果有忽略初始化特性
                if (tenantAtt != null && tenantAtt.configId.ToString() != config.ConfigId) continue;//如果特性存在并且租户ID不是当前数据库ID
                var splitTable = entityType.GetCustomAttribute<SplitTableAttribute>();//获取自动分表特性
                if (splitTable == null)//如果特性是空
                    db.CodeFirst.InitTables(entityType);//普通创建
                else
                    db.CodeFirst.SplitTables().InitTables(entityType);//自动分表创建
            }

        }

        /// <summary>
        /// 初始化种子数据
        /// </summary>
        /// <param name="config"></param>
        private static void InitSeedData(ISqlSugarClient sqlClient, SqlSugarSettings config)
        {
            // 获取所有种子配置-初始化数据
            var types = AssemblyManager.FindTypes(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDeriveClassFrom(typeof(ISqlSugarSeedData<>))); //获得seeddata类型
            if (types == null || !types.Any()) return; //当没有相关类时，则返回
            foreach (var type in types)//遍历种子类
            {
                //使用与指定参数匹配程度最高的构造函数来创建指定类型的实例。
                var instance = Activator.CreateInstance(type); //对相关类型进行实例化
                var entityType = type.GetInterfaces().First(m => m.IsGenericType).GetGenericArguments().First();//获取实体类型
                var tenantAtt = entityType.GetCustomAttribute<TenantAttribute>();//获取sqlsugar租户特性
                if (tenantAtt != null && tenantAtt.configId.ToString() != config.ConfigId) continue;//如果不是当前租户的就下一个

                var method = type.GetMethod("ProducedSeedData"); //获得相关类型的方法
                if (method == null) continue;//当没有该方法时，继续执行下一个类型
                object[] parameters = new object[] { sqlClient };//方法的参数
                method.Invoke(instance, parameters); //执行相关类的种子函数         
            }

        }

        /// <summary>
        /// 实体拓展配置,自定义类型多库兼容
        /// </summary>
        /// <param name="db"></param>
        /// <param name="config"></param>
        private static void ExternalServicesSetting(SqlSugarScopeProvider db, SqlSugarSettings config)
        {
            Dictionary<string, PropertyInfo> keyValues = new Dictionary<string, PropertyInfo>();
            var type = typeof(ICreationAudited);
            var creationAuditedProperties = type.GetProperties().ToList(); //创建属性 
            type = typeof(IModificationAudited);
            var modificationAuditedProperties = type.GetProperties().ToList(); //更新属性
            type = typeof(IDeletionAudited);
            var deletionAuditedProperties = type.GetProperties().ToList(); //删除属性
            //db.QueryFilter.AddTableFilter<IDeletionAudited>(it => it.IsDeleted == false); //过淲掉软删除的数据
            db.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices
            {
               
                // 处理表
                EntityNameService = (type, entity) =>
                {
                    if (config.IsUnderLine && !entity.DbTableName.Contains('_'))
                        entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName); // 驼峰转下划线
                },
                //自定义类型多库兼容
                EntityService = (c, p) =>
                {
                    if (c.DeclaringType != null)
                    {
                        var property = creationAuditedProperties.FirstOrDefault(m => m.Name == c.Name);
                        if (property == null) property = modificationAuditedProperties.FirstOrDefault(m => m.Name == c.Name);
                        if (property == null) property = deletionAuditedProperties.FirstOrDefault(m => m.Name == c.Name);

                        if ((c.DeclaringType.IsBaseOn<ICreationAudited>() || c.DeclaringType.IsBaseOn<IModificationAudited>() || c.DeclaringType.IsBaseOn<IDeletionAudited>()) && property != null)
                        {
                            if (property.HasAttribute<DescriptionAttribute>())
                            {
                                var attr = property.GetAttribute<DescriptionAttribute>();
                                if (attr != null && !string.IsNullOrWhiteSpace(attr.Description)) p.ColumnDescription = attr.Description;
                            }
                            //处理在核心库中定义的审计属性，如果是可空类型，则修改为可空
                            if (c.PropertyType.IsBaseOn(typeof(Nullable<>)) || c.PropertyType.IsBaseOn<string>())
                            {
                                p.IsNullable = true;
                            }
                        }
                    }

                    //如果是mysql并且是varchar(max) 已弃用
                    //if (config.DbType == SqlSugar.DbType.MySql && (p.DataType == SqlsugarConst.NVarCharMax))
                    //{
                    //    p.DataType = SqlsugarConst.LongText;//转成mysql的longtext
                    //}
                    //else if (config.DbType == SqlSugar.DbType.Sqlite && (p.DataType == SqlsugarConst.NVarCharMax))
                    //{
                    //    p.DataType = SqlsugarConst.Text;//转成sqlite的text
                    //}
                    //默认不写IsNullable为非必填
                    //if (new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable)
                    //    p.IsNullable = true;
                    if (config.IsUnderLine && !p.IsIgnore && !p.DbColumnName.Contains('_'))
                        p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName); // 驼峰转下划线
                }
            };
        }


        /// <summary>
        /// Aop设置
        /// </summary>
        /// <param name="db"></param>
        public static void AopSetting(SqlSugarScopeProvider db)
        {
            var config = db.CurrentConnectionConfig;

            //db.QueryFilter.AddTableFilter<IDeletionAudited>(item => item.de);


            // 设置超时时间
            // db.Ado.CommandTimeOut = 30; //30秒
            db.Ado.CommandTimeOut = 30 * 60;

            // 打印SQL语句
            db.Aop.OnLogExecuting = (sql, pars) =>
            {
                //如果不是开发环境就打印sql
                if (EasyApp.HostEnvironment.IsDevelopment())
                {
                    if (sql.StartsWith("SELECT"))
                    {
                        WriteSqlLog($"查询{config.ConfigId}库操作", ConsoleColor.Green);
                    }
                    if (sql.StartsWith("UPDATE") || sql.StartsWith("INSERT"))
                    {
                        WriteSqlLog($"修改{config.ConfigId}库操作", ConsoleColor.Blue);
                    }
                    if (sql.StartsWith("DELETE"))
                    {
                        WriteSqlLog($"删除{config.ConfigId}库操作", ConsoleColor.Red);
                    }
                    string cmdSql = UtilMethods.GetSqlString(config.DbType, sql, pars);
                    cmdSql = Regex.Replace(cmdSql, @"^\s+", "", RegexOptions.Multiline);
                    Console.WriteLine(cmdSql);
                    WriteSqlLog($"{config.ConfigId}库操作结束", null);
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine();
                }
            };
            //异常
            db.Aop.OnError = (ex) =>
            {
                //如果不是开发环境就打印日志
                if (EasyApp.HostEnvironment.IsDevelopment())
                {
                    if (ex.Parametres == null) return;
                    var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
                    WriteSqlLog($"{config.ConfigId}库操作异常", ConsoleColor.Red);
                    string cmdSql = UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n";
                    cmdSql = Regex.Replace(cmdSql, @"^\s+", "", RegexOptions.Multiline);
                    Console.WriteLine(cmdSql);
                    Console.ForegroundColor = ConsoleColor.White;
                }
            };
            //插入和更新过滤器
            db.Aop.DataExecuting = (oldValue, entityInfo) =>
            {
                /*
                //设计审计属性 
                var type = entityInfo.EntityValue.GetType();//获得当前操作的类型
                if (type.IsGenericTypeDefinition)
                {
                    type = type.GetGenericParameterConstraints()[0];
                }
                if (entityInfo.OperationType == DataFilterType.InsertByObject)
                {
                    //新增操作
                    if (type.IsBaseOn<ICreationAudited>())
                    {
                        if (entityInfo.EntityName == "CreatorBy" || entityInfo.EntityName == "CreationTime")
                        {
                            var creationAudited = entityInfo.EntityValue as ICreationAudited;
                            if (entityInfo.EntityName == "CreatorBy") creationAudited.CreatorBy = EasyApp.UserId;
                            if (entityInfo.EntityName == "CreationTime") creationAudited.CreationTime = DateTime.Now;
                        }
                    }
                    if (type.IsBaseOn<IDeletionAudited>())
                    {
                        if (entityInfo.EntityName == "IsDeleted")
                        {
                            var deletionAudited = entityInfo.EntityValue as IDeletionAudited;
                            deletionAudited.IsDeleted = false;
                        }
                    }
                }
                else if (entityInfo.OperationType == DataFilterType.UpdateByObject)
                {
                    //更新操作
                    if (type.IsBaseOn<IModificationAudited>())
                    {
                        if (entityInfo.EntityName == "LastModificationBy" || entityInfo.EntityName == "LastModificationTime")
                        {
                            var modificationAudited = entityInfo.EntityValue as IModificationAudited;
                            if (entityInfo.EntityName == "LastModificationBy") modificationAudited.LastModificationBy = EasyApp.UserId;
                            if (entityInfo.EntityName == "LastModificationTime") modificationAudited.LastModificationTime = DateTime.Now;
                        }
                    }
                }
                else if (entityInfo.OperationType == DataFilterType.DeleteByObject)
                {
                    //删除操作
                    if (type.IsBaseOn<IDeletionAudited>())
                    {
                        if (entityInfo.EntityName == "DeletionTime" || entityInfo.EntityName == "DeletionBy" || entityInfo.EntityName == "IsDeleted") {
                            var deletionAudited = entityInfo.EntityValue as IDeletionAudited;
                            if (entityInfo.EntityName == "DeletionTime") deletionAudited.DeletionTime = DateTime.Now;
                            if (entityInfo.EntityName == "DeletionBy") deletionAudited.DeletionBy = EasyApp.UserId;
                            if (entityInfo.EntityName == "IsDeleted") deletionAudited.IsDeleted = true; //软删除 
                        }
                        entityInfo.OperationType = DataFilterType.UpdateByObject;//更改为更新操作
                    }
                }
                */
            };

            //查询数据转换
            db.Aop.DataExecuted = (value, entity) =>
            {
                //if (entity.Entity.Type == typeof(SysUser))
                //{
                //    /*
                //    //如果手机号不为空
                //    if (entity.GetValue(nameof(SysUser.Phone)) != null)
                //    {
                //        //手机号数据转换
                //        var phone = CryptogramUtil.Sm4Decrypt(entity.GetValue(nameof(SysUser.Phone)).ToString());
                //        entity.SetValue(nameof(SysUser.Phone), phone);
                //    }
                //    //如果密码不为空
                //    if (entity.GetValue(nameof(SysUser.Password)) != null)
                //    {
                //        //密码数据转换
                //        var passwd = CryptogramUtil.Sm4Decrypt(entity.GetValue(nameof(SysUser.Password)).ToString());
                //        entity.SetValue(nameof(SysUser.Password), passwd);
                //    }
                //    */
                //}
            };
        }


        /// <summary>
        /// 实体更多配置
        /// </summary>
        /// <param name="db"></param>
        private static void MoreSetting(SqlSugarScopeProvider db)
        {
            db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings
            {
                SqlServerCodeFirstNvarchar = true,//设置默认nvarchar
            };
        }

        /// <summary>
        /// 过滤器设置
        /// </summary>
        /// <param name="db"></param>
        public static void FilterSetting(SqlSugarScopeProvider db)
        {
            // 假删除过滤器
            //LogicDeletedEntityFilter(db);
        }


        private static void WriteSqlLog(string msg, ConsoleColor? consoleColor)
        {
            msg = Regex.Replace(msg, @"^\s+", "", RegexOptions.Multiline);
            if (consoleColor != null && consoleColor.HasValue) Console.ForegroundColor = consoleColor.Value;
            Console.WriteLine($"=============={msg}==============");
        }

    }




}

